//
//  PlayScene.m
//  MinusTheBox
//
//  Created by Chi Ho Chiu on 15/4/12.
//  Copyright 2012 Individual. All rights reserved.
//

#import "PlayScene.h"
#import "ModalAlert.h"


@implementation PlayScene
@synthesize layer;
@synthesize numberArray;
@synthesize gameState;
@synthesize maxStep, currentStep;
@synthesize historySteps;
-(void) dealloc
{
	[historySteps release];
	[numberArray release];
	[layer release];
	[super dealloc];
}

-(id) init
{
	if (self = [super init])
	{
		//TODO: Remove it after debug
		//[[GameManager sharedGameManager] setCurrentLevel:1];
		
		[self loadLevel];	//Load all info from pList
		
		//Init Layer
		PlayLayer *tempLayer = [[PlayLayer alloc] initWithMaxStep:maxStep withDelegate:self];
		self.layer = tempLayer;
        [self addChild:layer];
		[layer showBackToPreviousStepSprite:NO];
		[layer showHintBtn:YES];
		
		[tempLayer release];
		
		//Init member var
		self.currentStep = 0;
		
		[layer placeBox:numberArray];
	}
	
	return self;
}

#pragma mark - Init
-(void) loadLevel
{
	self.numberArray = [Box2DArray node];
	
	//Get whole pList
	NSString *pListPath = [[NSBundle mainBundle] pathForResource:@"level" ofType:@"plist"];
	NSDictionary *pListDict = [NSDictionary dictionaryWithContentsOfFile:pListPath];
	
	//Get Level Info
	int currentLevel = [[GameManager sharedGameManager] currentLevel];
	NSDictionary *levelDict = [pListDict objectForKey:[NSString stringWithFormat:@"%d", currentLevel]];
	
	//Get Max Step Value
	NSNumber *step = [levelDict objectForKey:@"MaxStep"];
	self.maxStep = [step intValue];
	
	//Get Box Array
	NSArray *boxArray = [levelDict objectForKey:@"Box"];
	
	//Get All Box Position
	for(int i=0; i<boxArray.count; i++)
	{
		NSDictionary *boxDict = [boxArray objectAtIndex:i];
		
		int column = [[boxDict objectForKey:@"Column"] intValue];
		int row = [[boxDict objectForKey:@"Row"] intValue];
		NSNumber *value = [boxDict objectForKey:@"Value"];
		
		[numberArray addObjectInColumn:column row:row value:value];	//Add to Box2DArray
	}
	
	//Init HistorySteps with the first step
	HistorySteps *tempHistoryStep = [[HistorySteps alloc] initWithFirstStep:numberArray];
	self.historySteps = tempHistoryStep;
	[tempHistoryStep release];
}

#pragma mark - Core Logic Flow
-(BOOL) processMinusInColumn:(int)col row:(int)row
{
	NSLog(@"Start Minus");
	//Iterate the entire column
	for(int i = 0; i < MAX_BOX_ROW; i++)
	{
		id obj = [numberArray getObjectInColumn:col row:i];
		//if(![obj isEqual:[NSNull null]])
		if(obj != [NSNull null])
		{
			//Get the value of the Box
			NSNumber *valObj = (NSNumber *)obj;
			int oriNum = [valObj intValue];
			
			//Update the value of the Box
			int newNum = oriNum - 1;	//Decrease By 1
			NSNumber *newObj = [NSNumber numberWithShort:newNum];
			[numberArray updateObjectInColumn:col row:i value:newObj];
			
			//Update UI
			[layer updateBoxNumberFrom:oriNum to:newNum inColumn:col inRow:i];
		}
	}

	//Iterate the entire row
	for(int i = 0; i <MAX_BOX_COLUMN; i++)
	{
		//Skip since it updated when iterate entire column
		if(i == col)
			continue;
		
		id obj = [numberArray getObjectInColumn:i row:row];
		//if(![obj isEqual:[NSNull null]])
		if(obj != [NSNull null])
		{
			//Get the value of the Box
			NSNumber *valObj = (NSNumber *)obj;
			int oriNum = [valObj intValue];
			
			//Update the value of the Box
			int newNum = oriNum - 1;	//Decrease By 1
			NSNumber *newObj = [NSNumber numberWithShort:newNum];
			[numberArray updateObjectInColumn:i row:row value:newObj];
			
			//Update UI
			[layer updateBoxNumberFrom:oriNum to:newNum inColumn:i inRow:row];
		}
	}
	
	return YES;	//Must at least something minus, always return YES
}

-(BOOL) processExplodeZero
{
	NSLog(@"Start Explode Zero");
	BOOL isExploded = NO;
	for(int col = 0; col < MAX_BOX_COLUMN; col++)
	{
		for(int row = 0; row < MAX_BOX_ROW; row++)
		{
			id obj = [numberArray getObjectInColumn:col row:row];
			//if(![obj isEqual:[NSNull null]])
			if(obj != [NSNull null])
			{
				NSNumber *valObj = (NSNumber *)obj;
				if([valObj intValue] == 0)	//Check if any 0 value
				{
					isExploded = YES;
					
					//Update the Value of the Box
					[numberArray updateObjectInColumn:col row:row value:[NSNull null]];
					
					//Update UI
					[layer explodeZeroBoxInColumn:col row:row];
				}
			}
		}
	}
	return isExploded;
}

-(BOOL) processFall
{
	NSLog(@"Start Fall");
	
	BOOL isFall = NO;
	for(int col = 0; col < MAX_BOX_COLUMN; col++)
	{
		for(int row = 1; row < MAX_BOX_ROW; row++)	//First row must not fall as already on ground
		{
			id obj = [numberArray getObjectInColumn:col row:row];
			if(obj != [NSNull null])	//If Null, skip to next directly
			{
				NSNumber *number = (NSNumber *)obj;	//Get the box number
				
				//Check if the below box is NULL, fall to the bottom one with NULL
				for(int i = 0; i < row; i++)
				{
					id belowObj = [numberArray getObjectInColumn:col row:i];
					if(belowObj == [NSNull null])	//If Null, move to this position
					{
						[numberArray updateObjectInColumn:col row:i value:number];	//Update the new position value
						[numberArray updateObjectInColumn:col row:row value:[NSNull null]];	//Update the old position to Null
						
						[layer fallBoxInColumn:col fromRow:row toRow:i];	//Call Layer to fall the box
						
						isFall = YES;	//Set to YES if something fall
						break;
					}
				}
			}
		}
	}
	
	return isFall;
}

-(BOOL) processChain
{
	NSLog(@"Start Chain");
	
	BOOL isChain = NO;
	
	Box2DArray *pendingChainBoxArray = [Box2DArray node];
	
	//Check for any chain on column first
	for(int col = 0; col < MAX_BOX_COLUMN; col++)
	{
		int chainStartRow = 0;	//Start Row must be zero
		int numChain = 1;	//At least one
		int chainBoxNumber = -1;	//Init as -1
		for(int row = 0; row < MAX_BOX_ROW; row++)
		{
			id obj = [numberArray getObjectInColumn:col row:row];
			if(obj != [NSNull null])
			{
				NSNumber *numObj = (NSNumber *)obj;
				int boxNum = [numObj intValue];
				
				if(boxNum == chainBoxNumber)	//If equal to last box, which means chain started
				{
					numChain++;	//Add chainBoxNumber only
				}
				else	//Break the chain
				{
					//Check if chain box is equal or greater than 3
					if(numChain >= 3)
					{
						NSNumber *chainObj = [NSNumber numberWithShort:chainBoxNumber];	
						for(int i=0; i<numChain; i++)	//Iterate number of times of "chain box"
						{
							NSLog(@"Chaining col:%d row:%d", col, (chainStartRow + i));
							[pendingChainBoxArray addObjectInColumn:col row:(chainStartRow + i) value:chainObj];	//Update the value
						}
						isChain = YES;	//Set to Yes if at least one chained
					}
					
					chainBoxNumber = boxNum;		//Update the last box number
					chainStartRow = row;			//Update the last box row
					numChain = 1;					//Restore the numChain to 1
				}
			}
			else
			{
				break;
			}
		}
		
		//Maybe the top of box is still chaining
		//so check if chain box is equal or greater than 3
		if(numChain >= 3)
		{
			NSNumber *chainObj = [NSNumber numberWithShort:chainBoxNumber];	
			for(int i=0; i<numChain; i++)	//Iterate number of times of "chain box"
			{
				NSLog(@"Chaining col:%d row:%d", col, (chainStartRow + i));
				[pendingChainBoxArray addObjectInColumn:col row:(chainStartRow + i) value:chainObj];	//Update the value
			}
		}
	}
	
	//Check for any chain on row 
	for(int row = 0; row < MAX_BOX_ROW; row++)
	{
		int chainStartColumn = 0;	//Start Column must be zero
		int numChain = 1;	//At least one
		int chainBoxNumber = -1;	//Init as -1
		for(int col = 0; col < MAX_BOX_COLUMN; col++)
		{
			id obj = [numberArray getObjectInColumn:col row:row];
			if(obj != [NSNull null])
			{
				NSNumber *numObj = (NSNumber *)obj;
				int boxNum = [numObj intValue];
				
				if(boxNum == chainBoxNumber)	//If equal to last box, which means chain started
				{
					numChain++;	//Add chainBoxNumber only
				}
				else	//Break the chain
				{
					//Check if chain box is equal or greater than 3
					if(numChain >= 3)
					{
						NSNumber *chainObj = [NSNumber numberWithShort:chainBoxNumber];	
						for(int i=0; i<numChain; i++)	//Iterate number of times of "chain box"
						{
							NSLog(@"Chaining col:%d row:%d", (chainStartColumn +i), row);
							[pendingChainBoxArray addObjectInColumn:(chainStartColumn + i) row:row value:chainObj];	//Update the value
						}
						isChain = YES;	//Set to Yes if at least one chained
					}
					
					chainBoxNumber = boxNum;		//Update the last box number
					chainStartColumn = col;			//Update the last box column
					numChain = 1;					//Restore the numChain to 1
				}
			}
		}	
		
		//Maybe the top of box is still chaining
		//so check if chain box is equal or greater than 3
		if(numChain >= 3)
		{
			NSNumber *chainObj = [NSNumber numberWithShort:chainBoxNumber];	
			for(int i=0; i<numChain; i++)	//Iterate number of times of "chain box"
			{
				NSLog(@"Chaining col:%d row:%d", (chainStartColumn +i), row);
				[pendingChainBoxArray addObjectInColumn:(chainStartColumn + i) row:row value:chainObj];	//Update the value
			}
			isChain = YES;	//Set to Yes if at least one chained
		}
			
	}
	
	//Update Everything
	for(int col = 0; col < MAX_BOX_COLUMN; col++)
	{
		for(int row = 0; row < MAX_BOX_ROW; row++)
		{
			id obj = [pendingChainBoxArray getObjectInColumn:col row:row];
			if(obj != [NSNull null])
			{
				[layer chainBoxInColumn:col row:row];	//Call Layer to start animating
				[numberArray removeObjectInColumn:col row:row];	//Remove from numberArray
			}
		}
	}
	
	return isChain;
}

-(void) completeLevel
{
	if(currentStep <= maxStep)	//Level Completed
	{
		[ModalAlert Tell:@"Next Level" 
				 onLayer:self.layer 
				 okBlock:^void{}];
	}
	else	//Fail
	{
		[ModalAlert Tell:@"Retry" 
				 onLayer:self.layer 
				 okBlock:^ void { }];
	}
}

-(void) onStepCompleted
{
	//Increase Step by 1 and update UI
	currentStep++;
	[layer updateCurrentStep:currentStep maxStep:maxStep];
	[layer showBackToPreviousStepSprite:YES];
	[layer showHintBtn:NO];
	
	//Add to History Steps with the new step
	[historySteps addNewStep:numberArray];
	
	//Enable Layer to receive touch again
	[layer setEnableTouch:YES];
	
	//TODO: Check if game is completed
	NSLog(@"Finished All Step");

	if([numberArray isAllNull])	//If completed level
		[self completeLevel];
}

#pragma mark - Button Clicked Logic
-(void) useHint
{
	
}

-(void) retryLevel
{
	
}

#pragma mark - PlayLayerDelegate
-(void) onClickedBoxInColumn:(int)col row:(int)row
{
	//Disable Touch in Layer
	[layer setEnableTouch:NO];
	
	//Start Minus
	[self processMinusInColumn:col row:row];
}

-(void) onSelectedBackToPreviousStep:(id)sender
{
	//Update the member var
	currentStep--;
	[layer updateCurrentStep:currentStep maxStep:maxStep];
	
	//Hide Back To previous Button if no more previous step
	if(currentStep == 0)
	{
		[layer showBackToPreviousStepSprite:NO];
		[layer showHintBtn:YES];
	}
	
	//Update the value of numberArray
	Box2DArray *lastStep = [historySteps getPreviousStep];
	self.numberArray = lastStep;
	
	//Update UI
	[layer removeAllBox];	//Remove all box from UI
	[layer placeBox:lastStep];	//Place new box in UI
	
	//Remove last step
	[historySteps removeLastStep];
}

-(void) onSelectedHint:(id)sender
{
	
}

-(void) onSelectedBack:(id)sender
{
	[[CCDirector sharedDirector] popScene];
}

-(void) onSelectedRetry:(id)sender
{
	
}

-(void) onSelectedNextLevel:(id)sender
{

}

-(void) onFallBoxCompleted
{
	NSLog(@"Finished Fall");
	BOOL isChain = [self processChain];
	
	//If nothing chain, which means the this flow completed and ended here
	//If something chain, waits chain action completed
	if(!isChain)
	{
		[self onStepCompleted];
	}
}

-(void) onChainBoxCompleted
{
	NSLog(@"Finished Chain");
	BOOL isFall =[self processFall];
	
	//If nothing fall, which means the this flow completed and ended here
	//If something falled, waits fall action completed
	if(!isFall)
	{
		[self onStepCompleted];
	}
}

-(void) onExplodeZeroBoxCompleted
{
	NSLog(@"Finished Explode Zero");
	BOOL isFall = [self processFall];
	
	//If nothing fall, directly check if any chain
	if(!isFall)
	{
		BOOL isChain = [self processChain];
		
		//If nothing chain, which means the this flow completed and ended here
		//If something chain, waits chain action completed
		if(!isChain)
		{
			[self onStepCompleted];
		}
	}
}

-(void) onUpdatedBoxNumberCompleted
{
	NSLog(@"Finished Minus");
	BOOL isExploded = [self processExplodeZero];

	if(!isExploded)	//If nothing explode, which means no need to wait for action
	{
		BOOL isChain = [self processChain];	//Directly go to chain explode State
		if(!isChain)
		{
			[self onStepCompleted];	//Step Completed when no more chain
		}
	}
}

@end
